package com.vca.service.service.Impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.vca.common.constants.Constants;
import com.vca.common.constants.SysGroupDataConstants;
import com.vca.common.exception.VcaException;
import com.vca.common.model.course.CourseAbout;
import com.vca.common.model.course.CoursePackageRelation;
import com.vca.common.model.system.SystemAttachment;
import com.vca.common.model.talk.Talk;
import com.vca.common.model.talk.TalkInfo;
import com.vca.common.model.talk.TalkScheduling;
import com.vca.common.model.user.User;
import com.vca.common.model.user.UserCollection;
import com.vca.common.request.AdminCommonRequest;
import com.vca.common.request.CourseAboutAddRequest;
import com.vca.common.request.PageParamRequest;
import com.vca.common.request.TalkAddRequest;
import com.vca.common.response.*;
import com.vca.common.utils.PageUtils;
import com.vca.common.vo.SchedulingVo;
import com.vca.common.vo.TalkInfoVo;
import com.vca.service.dao.talk.TalkDao;
import com.vca.service.service.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * <p>
 * 讲座表 服务实现类
 * </p>
 *
 * @author chenBing
 * @since 2022-11-03
 */
@Service
public class TalkServiceImpl extends ServiceImpl<TalkDao, Talk> implements TalkService {
    @Resource
    private TalkDao dao;

    @Autowired
    private SystemGroupDataService systemGroupDataService;

    @Autowired
    private VcaOrderService vcaOrderService;

    @Autowired
    private TalkSchedulingService talkSchedulingService;

    @Autowired
    private TalkInfoService talkInfoService;

    @Autowired
    private CourseAboutService courseAboutService;

    @Autowired
    private CourseService courseService;

    @Autowired
    private UserService userService;

    @Autowired
    private UserCollectionService userCollectionService;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private SystemAttachmentService systemAttachmentService;

    @Autowired
    private SystemConfigService systemConfigService;

    /**
     * @Description:讲座分页列表
     * @Author: chenBing
     * @Date: 2022/11/3
     */
    @Override
    public PageInfo<TalkResponse> getList(String language,PageParamRequest pageParamRequest) {
        LambdaQueryWrapper<Talk> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Talk::getStatus, 1).eq(Talk::getIsRecycle, 0).eq(Talk::getIsDeleted, 0);
        List<Talk> talkList = list(lqw);

        List<TalkResponse> talkResponseList = new ArrayList<>();
        if (talkList.size() <= 0) {
            return fenYe(talkResponseList, pageParamRequest);
        }
        for (Talk talk : talkList) {
            TalkResponse talkResponse = info(language,talk.getId(), "talk_list", null);
            if (talkResponse == null) {
                continue;
            }
            talkResponseList.add(talkResponse);
        }

        List<TalkResponse> talkResponses = new ArrayList<>();
        for (TalkResponse talkResponse : talkResponseList) {
            if (talkResponse.getSchedulingDate().compareTo(DateUtil.format(new Date(), "yyyy-MM-dd")) == 0) {
                String format = DateUtil.format(new Date(), "HH:mm");
                if (talkResponse.getSchedulingEndTime().compareTo(format) <= -1) {
                    talkResponses.add(talkResponse);
                }
            }
        }
        talkResponseList.removeAll(talkResponses);
        return fenYe(talkResponseList, pageParamRequest);
    }

    @Override
    public List<TalkResponse> getListCalendar(String date) {
        LambdaQueryWrapper<Talk> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Talk::getStatus, 1).eq(Talk::getIsRecycle, 0).eq(Talk::getIsDeleted, 0);
        if (StringUtils.isNotBlank(date)) {
            List<TalkScheduling> schedulingList = talkSchedulingService.list(new LambdaQueryWrapper<TalkScheduling>()
                    .eq(TalkScheduling::getIsDeleted, false)
                    .eq(TalkScheduling::getStatus, true).eq(TalkScheduling::getIsCancel, false)
                    .eq(TalkScheduling::getSchedulingDate, date)
                    .ge(TalkScheduling::getQuota, 0));
            List<TalkScheduling> schedulingResult = new ArrayList<>();
            schedulingList.forEach(scheduling -> {
                if (com.vca.common.utils.DateUtil.getSchedulingStatus(scheduling.getSchedulingDate(), scheduling.getSchedulingStartTime(), scheduling.getSchedulingEndTime()) != 0) {
                    schedulingResult.add(scheduling);
                }
            });
            schedulingList.retainAll(schedulingResult);
            List<Long> talkIds = new ArrayList<>();
            if (schedulingList.size() > 0) {
                schedulingList.forEach(s -> {
                    talkIds.add(s.getTalkId());
                });
                lqw.in(Talk::getId, talkIds);
            }
        }
        List<Talk> talkList = list(lqw);
        List<TalkResponse> talkResponseList = new ArrayList<>();
        if (talkList.size() <= 0) {
            return null;
        }
        for (Talk talk : talkList) {
            TalkResponse talkResponse = info("",talk.getId(), "talk_list", date);
            if (talkResponse == null) {
                continue;
            }
            talkResponseList.add(talkResponse);
        }
        List<TalkResponse> talkResponses = new ArrayList<>();
        for (TalkResponse talkResponse : talkResponseList) {
            if (talkResponse.getSchedulingDate().compareTo(DateUtil.format(new Date(), "yyyy-MM-dd")) == 0) {
                String format = DateUtil.format(new Date(), "HH:mm");
                if (talkResponse.getSchedulingStartTime().compareTo(format) <= -1) {
                    talkResponses.add(talkResponse);
                }
            }
        }
        talkResponseList.removeAll(talkResponses);
        return talkResponseList;
    }

    /**
     * @Description:处理分页
     * @Author: chenBing
     * @Date: 2022/11/3
     */
    private PageInfo<TalkResponse> fenYe(List<TalkResponse> talkResponseList, PageParamRequest pageParamRequest) {
        talkResponseList = talkResponseList.stream()
                .sorted(Comparator.comparing(TalkResponse::getSchedulingDate)
                        .thenComparing(Comparator.comparing(TalkResponse::getSchedulingStartTime))
                        .thenComparing(Comparator.comparing(TalkResponse::getRemainingSeatCount).reversed())).collect(Collectors.toList());
        return startPage(talkResponseList, pageParamRequest.getPage(), pageParamRequest.getLimit());
    }

    /**
     * @Description:分页
     * @Author: chenBing
     * @Date: 2022/11/3
     */
    public <T> PageInfo<T> startPage(List<T> list, Integer pageNum, Integer pageSize) {
        //创建Page类
        com.github.pagehelper.Page page = new com.github.pagehelper.Page(pageNum, pageSize);
        //为Page类中的total属性赋值
        page.setTotal(list.size());
        //计算当前需要显示的数据下标起始值
        int startIndex = (pageNum - 1) * pageSize;
        int endIndex = Math.min(startIndex + pageSize, list.size());
        //从链表中截取需要显示的子链表，并加入到Page
        if (startIndex < endIndex) {
            page.addAll(list.subList(startIndex, endIndex));
        }
        //以Page创建PageInfo
        PageInfo pageInfo = new PageInfo<>(page);
        return pageInfo;
    }

    /**
     * @Description:讲座详情
     * @Author: chenBing
     * @Date: 2022/11/3
     */
    @Override
    public TalkResponse info(String language,Long talkId) {
        return info(language,talkId, "talk_info_one", null);
    }

    /**
     * 讲座管理
     *
     * @param request
     * @param pageParamRequest
     * @return
     * @author Li
     * @date 2022/11/14 10:01
     */
    @Override
    public PageInfo<TalkAdminListResponse> getAdminList(AdminCommonRequest request, PageParamRequest pageParamRequest) {
        List<TalkAdminListResponse> talkAdminList = new ArrayList<>();
        LambdaUpdateWrapper<Talk> wrapper = new LambdaUpdateWrapper();
        wrapper.eq(Talk::getIsDeleted, 0);
        //条件
        if (ObjectUtil.isNotEmpty(request.getType())) {
            wrapper.eq(Talk::getTalkType, request.getType());
        }
        if (ObjectUtil.isNotEmpty(request.getStatus())) {
            wrapper.eq(Talk::getStatus, request.getStatus());
        }
        if (ObjectUtil.isNotEmpty(request.getKeywords())) {
            List<Integer> ids = dao.fuzzySearch(request.getKeywords());
            if (ObjectUtil.isEmpty(ids)) {
                return PageUtils.startPage(talkAdminList, pageParamRequest.getPage(), pageParamRequest.getLimit());
            }
            wrapper.in(Talk::getId, ids);
        }
        //获取课程配置
        Map<String, List<HashMap<String, Object>>> courseAdminConfig = systemGroupDataService.getCourseAdminConfig();
        List<HashMap<String, Object>> address = courseAdminConfig.get("addressList");
        List<Talk> talks = dao.selectList(wrapper);
        talks.forEach(talk -> {
            TalkAdminListResponse response = new TalkAdminListResponse();
            //将属性拷贝
            BeanUtils.copyProperties(talk, response);
            response.setTalkType(talk.getTalkType());
            response.setPrice(talk.getPrice().toString());
            address.forEach(e -> {
                //遍历地址配置获取到相对应的
                Map map = JSON.parseObject(JSONObject.toJSONString(e), Map.class);
                if (map.get("id").equals(talk.getAddressId())) {
                    response.setAddress(map.get("courseAddress").toString() + map.get("courseAddressInfo").toString());
                }
            });
            // TODO: 2022/11/3 设置talkInfo
            TalkInfo talkInfo = talkInfoService.getOne(new LambdaQueryWrapper<TalkInfo>().eq(TalkInfo::getTalkId, talk.getId()));
            TalkInfoVo talkInfoVo = new TalkInfoVo();
            BeanUtils.copyProperties(talkInfo, talkInfoVo);
            talkInfoVo.setDetails(JSON.parseArray(talkInfo.getDetails()));
            // TODO: 2022/10/10 设置相关图集部分
//            talkInfoVo.setRelatedAtlas(JSONObject.parseArray(talkInfo.getRelatedAtlas()));
            response.setTalkInfo(talkInfoVo);
            response.setCourseType(response.getTalkType() == 1 ? "线下讲座" : "线上讲座");
            talkAdminList.add(response);
        });
        return PageUtils.startPage(talkAdminList.stream().sorted(Comparator.comparing(TalkAdminListResponse::getSort).reversed()).collect(Collectors.toList()), pageParamRequest.getPage(), pageParamRequest.getLimit());
    }

    /**
     * 修改排序
     *
     * @param talkId 讲座id
     * @param sort   排序
     * @return
     * @author Li
     * @date 2022/11/18 15:16
     */
    @Override
    public boolean updateSort(Integer talkId, Integer sort) {
        LambdaQueryWrapper<Talk> wrapper = new LambdaQueryWrapper();
        wrapper.eq(Talk::getId, talkId);
        wrapper.eq(Talk::getIsDeleted, 0);
        Talk talk = dao.selectOne(wrapper);
        if (ObjectUtil.isEmpty(talk)) {
            throw new VcaException("该讲座不存在");
        }
        talk.setSort(sort);
        return transactionTemplate.execute(e -> {
            dao.updateById(talk);
            return Boolean.TRUE;
        });
    }

    /**
     * 修改限量
     *
     * @param talkId    讲座id
     * @param seatCount 限量
     * @return
     * @author Li
     * @date 2022/11/18 15:16
     */
    @Override
    public boolean updateSeatCount(Integer talkId, Integer seatCount) {
        LambdaQueryWrapper<Talk> wrapper = new LambdaQueryWrapper();
        wrapper.eq(Talk::getId, talkId);
        wrapper.eq(Talk::getIsDeleted, 0);
        Talk talk = dao.selectOne(wrapper);
        if (ObjectUtil.isEmpty(talk)) {
            throw new VcaException("该讲座不存在");
        }
        talk.setQuota(seatCount);
        return transactionTemplate.execute(e -> {
            dao.updateById(talk);
            return Boolean.TRUE;
        });
    }

    /**
     * 上架讲座
     *
     * @param talkId 讲座id
     * @return
     * @author Li
     * @date 2022/11/18 15:16
     */
    @Override
    public boolean courseOnShell(Integer talkId) {
        LambdaQueryWrapper<Talk> wrapper = new LambdaQueryWrapper();
        wrapper.eq(Talk::getId, talkId);
        wrapper.eq(Talk::getIsDeleted, 0);
        Talk talk = dao.selectOne(wrapper);
        if (ObjectUtil.isEmpty(talk)) {
            throw new VcaException("该讲座不存在");
        }
        talk.setStatus(1);
        return transactionTemplate.execute(e -> {
            dao.updateById(talk);
            return Boolean.TRUE;
        });
    }

    /**
     * 下架讲座
     *
     * @param talkId 讲座id
     * @return
     * @author Li
     * @date 2022/11/18 15:16
     */
    @Override
    public boolean courseOffShell(Integer talkId) {
        LambdaQueryWrapper<Talk> wrapper = new LambdaQueryWrapper();
        wrapper.eq(Talk::getId, talkId);
        wrapper.eq(Talk::getIsDeleted, 0);
        Talk talk = dao.selectOne(wrapper);
        if (ObjectUtil.isEmpty(talk)) {
            throw new VcaException("该讲座不存在");
        }
        talk.setStatus(0);
        return transactionTemplate.execute(e -> {
            dao.updateById(talk);
            return Boolean.TRUE;
        });
    }

    /**
     * 添加课程
     *
     * @param request
     * @return
     * @author Li
     * @date 2022/11/18 15:38
     */
    @Override
    public boolean addTalk(TalkAddRequest request) {

        //去除阿里云前缀
        List<String> carouselMaps = new ArrayList();
        request.getCarouselMap().forEach(e -> {
            carouselMaps.add(systemAttachmentService.clearPrefix(e));
        });
        Talk talk = new Talk();
        BeanUtils.copyProperties(request, talk);
        talk.setStatus(0);
        if (ObjectUtil.isEmpty(talk.getSort())) {
            talk.setSort(0);
        }
        //去除阿里云前缀
        talk.setCoverImage(systemAttachmentService.clearPrefix(request.getCoverImage()));
        talk.setCarouselMap(systemAttachmentService.clearPrefix(JSONArray.parseArray(JSON.toJSONString(carouselMaps)).toJSONString()));
        talk.setMainPictureVideo(StringUtils.isNotBlank(request.getMainPictureVideo()) ? systemAttachmentService.clearPrefix(request.getMainPictureVideo()) : "");
        talk.setSharePoster(systemAttachmentService.clearPrefix(request.getSharePoster()));
        talk.setPrice(new BigDecimal(request.getPrice()));
        List<CourseAbout> courseAboutList = new ArrayList();
        AtomicReference<VcaException> vcaException = new AtomicReference();
        //将相关课程和商品根据0 = 课程 1=讲座 2=展览 3=商品 进行分组
        Map<Integer, List<CourseAboutAddRequest>> listMap = request.getCourseAboutAddRequests().stream().collect(Collectors.groupingBy(e -> e.getTypeCourse()));

        //验证判断添加的相关课程和商品是否存在
        courseAboutService.checkWhetherCourseAbout(listMap);

        //添加课程详情
        TalkInfo talkInfo = new TalkInfo();
        talkInfo.setDetails(systemAttachmentService.clearPrefix(request.getDetails()));
        talkInfo.setDetailsEn(systemAttachmentService.clearPrefix(request.getDetailsEn()));
        talkInfo.setIsDeleted(0);
        //事务
        return transactionTemplate.execute(e -> {
            //添加套课并获得 套课id
            save(talk);
            List<CoursePackageRelation> coursePackageRelations = new ArrayList();
            //添加套课和相关课程或商品的关系
            request.getCourseAboutAddRequests().forEach(g -> {
                CourseAbout courseAbout = new CourseAbout();
                BeanUtils.copyProperties(g, courseAbout);
                if (ObjectUtil.isEmpty(g.getSort())) {
                    courseAbout.setSort(0);
                }
                courseAbout.setTypeMainCourse(2);
                courseAbout.setAboutMainId(talk.getId());
                courseAboutList.add(courseAbout);
            });
            courseAboutService.addCourseAboutList(courseAboutList);
            talkInfo.setTalkId(talk.getId());
            talkInfoService.save(talkInfo);
            return Boolean.TRUE;
        });
    }

    /**
     * 根据id获取讲座信息
     *
     * @param talkId
     * @return
     * @author Li
     * @date 2022/11/22 10:25
     */
    @Override
    public TalkAdminResponse getTalk(Long talkId) {
        TalkAdminResponse response = new TalkAdminResponse();
        //查询课程是否存在
        LambdaQueryWrapper<Talk> wrapper = new LambdaQueryWrapper();
        wrapper.eq(Talk::getId, talkId);
        wrapper.eq(Talk::getIsRecycle, 0);
        Talk talk = dao.selectOne(wrapper);
        if (ObjectUtil.isEmpty(talk)) {
            throw new VcaException("课程不存在");
        }
        BeanUtils.copyProperties(talk, response);
        response.setPrice(talk.getPrice().toString());
        List<CourseAbout> courseAbouts = courseAboutService.list(new LambdaQueryWrapper<CourseAbout>().eq(CourseAbout::getAboutMainId, talkId).eq(CourseAbout::getIsDeleted, 0).eq(CourseAbout::getTypeMainCourse, 2));
        //将相关课程和商品根据0 = 课程 1=讲座 2=展览 3=商品 4=套课
        Map<Integer, List<CourseAbout>> listMap = courseAbouts.stream().collect(Collectors.groupingBy(e -> e.getTypeCourse()));
        //验证判断添加的相关课程和商品是否存在
        Map<String, List<HashMap<String, Object>>> courseAdminConfig = systemGroupDataService.getCourseAdminConfig();
        List<HashMap<String, Object>> address = courseAdminConfig.get("addressList");
        //获得地址信息
        address.forEach(e -> {
            Map map = JSON.parseObject(JSONObject.toJSONString(e), Map.class);
            if (map.get("id").equals(talk.getAddressId())) {
                response.setAddress(map.get("courseAddress").toString() + map.get("courseAddressInfo").toString());
            }
        });
        //课程详情
        TalkInfo talkInfo = talkInfoService.getOne(new LambdaQueryWrapper<TalkInfo>().eq(TalkInfo::getTalkId, talkId));
        response.setDetails(talkInfo.getDetails());
        response.setDetailsEn(talkInfo.getDetailsEn());
        //获得相关课程的信息
        List<CourseAboutAdminResponse> aboutList = courseAboutService.getAdminCourseAbout(listMap, courseAdminConfig);
        response.setCourseAboutAdminResponses(aboutList);
        return response;
    }

    /**
     * @param request
     * @Description:修改讲座
     * @Author: Li
     * @Date: 2022/11/22 14:56
     */
    @Override
    public boolean updateTalk(TalkAddRequest request) {

        //去除阿里云前缀
        List<String> carouselMaps = new ArrayList();
        request.getCarouselMap().forEach(e -> {
            carouselMaps.add(systemAttachmentService.clearPrefix(e));
        });
        Talk talk = dao.selectOne(new LambdaQueryWrapper<Talk>().eq(Talk::getId, request.getId()).eq(Talk::getIsDeleted, 0));
        if (ObjectUtil.isEmpty(talk)) {
            throw new VcaException("该课程不存在");
        }
        BeanUtils.copyProperties(request, talk);
        talk.setStatus(0);
        if (ObjectUtil.isEmpty(talk.getSort())) {
            talk.setSort(0);
        }
        //去除阿里云前缀
        talk.setCoverImage(systemAttachmentService.clearPrefix(request.getCoverImage()));
        talk.setCarouselMap(systemAttachmentService.clearPrefix(JSONArray.parseArray(JSON.toJSONString(carouselMaps)).toJSONString()));
        talk.setMainPictureVideo(StringUtils.isNotBlank(request.getMainPictureVideo()) ? systemAttachmentService.clearPrefix(request.getMainPictureVideo()) : "");
        talk.setSharePoster(systemAttachmentService.clearPrefix(request.getSharePoster()));
        talk.setPrice(new BigDecimal(request.getPrice()));
        List<CourseAbout> courseAboutList = new ArrayList();
        //将相关课程和商品根据0 = 课程 1=讲座 2=展览 3=商品 4=套课 进行分组
        Map<Integer, List<CourseAboutAddRequest>> listMap = request.getCourseAboutAddRequests().stream().collect(Collectors.groupingBy((CourseAboutAddRequest::getTypeCourse)));

        //校验添加的相关课程是否存在
        courseAboutService.checkWhetherCourseAbout(listMap);

        //添加课程详情
        TalkInfo talkInfo = talkInfoService.getOne(new LambdaQueryWrapper<TalkInfo>().eq(TalkInfo::getTalkId, request.getId()));
        talkInfo.setDetails(systemAttachmentService.clearPrefix(request.getDetails()));
        talkInfo.setDetailsEn(systemAttachmentService.clearPrefix(request.getDetailsEn()));
        request.getCourseAboutAddRequests().forEach(g -> {
            CourseAbout courseAbout = new CourseAbout();
            BeanUtils.copyProperties(g, courseAbout);
            if (ObjectUtil.isEmpty(g.getSort())) {
                courseAbout.setSort(0);
            }
            courseAbout.setAboutMainId(request.getId());
            courseAbout.setTypeMainCourse(2);
            if (ObjectUtil.isNotEmpty(g.getCourseAboutId())) {
                courseAbout.setId(g.getCourseAboutId());
            }
            courseAboutList.add(courseAbout);
        });
        //事务
        return transactionTemplate.execute(e -> {
            //添加课程并获得 课程id
            updateById(talk);
            //添加套课和相关课程或商品的关系
            courseAboutService.updateCourseAboutList(courseAboutList, request.getId());
            talkInfoService.updateById(talkInfo);
            return Boolean.TRUE;
        });
    }

    /**
     * 获得讲座头部数据
     *
     * @return
     * @author Li
     * @date 2022/11/23 09:16
     */
    @Override
    public List<AdminHeaderResponse> getHeader() {
        List<AdminHeaderResponse> headers = new ArrayList();
        AdminHeaderResponse active = new AdminHeaderResponse(0, "Active", 1, null);
        AdminHeaderResponse inActive = new AdminHeaderResponse(0, "InActive", 0, null);
        active.setCount(dao.selectList(new LambdaQueryWrapper<Talk>().eq(Talk::getStatus, 1).eq(Talk::getIsDeleted, 0)).size());
        inActive.setCount(dao.selectList(new LambdaQueryWrapper<Talk>().eq(Talk::getStatus, 0).eq(Talk::getIsDeleted, 0)).size());
        headers.add(active);
        headers.add(inActive);
        return headers;
    }

    /**
     * 删除讲座
     *
     * @param talkId
     * @return
     * @author Li
     * @date 2022/11/23 09:16
     */
    @Override
    public boolean deleteTalk(Long talkId) {
        Talk talk = this.checkTalk(talkId);
        List<TalkScheduling> schedulings = talkSchedulingService.list(new LambdaQueryWrapper<TalkScheduling>().eq(TalkScheduling::getTalkId, talk.getId()).eq(TalkScheduling::getIsDeleted, 0));
        if (ObjectUtil.isNotEmpty(schedulings)) {
            throw new VcaException("请先删除该讲座的排期");
        }
        List<CourseAbout> abouts = courseAboutService.list(new LambdaQueryWrapper<CourseAbout>().eq(CourseAbout::getAboutMainId, talkId).eq(CourseAbout::getIsDeleted, 0));
        talk.setIsDeleted(1);
        return transactionTemplate.execute(e -> {
            courseAboutService.delByids(abouts.stream().map(CourseAbout::getId).collect(Collectors.toList()));
            dao.update(talk, new LambdaUpdateWrapper<Talk>().eq(Talk::getId, talkId).set(Talk::getIsDeleted, 1));
            return Boolean.TRUE;
        });
    }

    @Override
    public List<Talk> getTalksAndDelete(List<Long> ids) {
        return dao.getTalks(ids);
    }

    /**
     * @Description:查询当前月份的日程
     * @author:chenbing
     * @date 2023/1/28 16:10
     */
    @Override
    public List<Integer> getCalendar(Integer month, Integer year) {
        List<Talk> talks = list(new LambdaQueryWrapper<Talk>().eq(Talk::getIsDeleted, 0).eq(Talk::getStatus, 1).eq(Talk::getIsRecycle, 0));
        if (talks.size() <= 0) {
            return null;
        }
        List<Long> talksIds = talks.stream().map(Talk::getId).collect(Collectors.toList());
        LambdaQueryWrapper<TalkScheduling> lqw = new LambdaQueryWrapper<>();
        lqw.select(TalkScheduling::getId, TalkScheduling::getTalkId, TalkScheduling::getSchedulingDate);
        lqw.eq(TalkScheduling::getIsDeleted, 0).eq(TalkScheduling::getIsCancel, 0).eq(TalkScheduling::getStatus, 1);
        lqw.ge(TalkScheduling::getSchedulingDate, com.vca.common.utils.DateUtil.getMonthStartDay(month, year));
        lqw.le(TalkScheduling::getSchedulingDate, com.vca.common.utils.DateUtil.getMonthEndDay(month, year));
        lqw.in(TalkScheduling::getTalkId, talksIds);
        lqw.groupBy(TalkScheduling::getSchedulingDate).orderByAsc(TalkScheduling::getSchedulingDate);
        List<TalkScheduling> schedulingList = talkSchedulingService.list(lqw);
        List<Integer> dates = new ArrayList<>();
        for (TalkScheduling talkScheduling : schedulingList) {
            Date date = com.vca.common.utils.DateUtil.strToDate(talkScheduling.getSchedulingDate(), Constants.DATE_FORMAT_DATE);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            int day = calendar.get(Calendar.DATE);
            dates.add(day);
        }
        return dates;
    }

    /**
     * 查询讲座是否存在
     *
     * @param talkId
     * @return
     */
    private Talk checkTalk(Long talkId) {
        LambdaQueryWrapper<Talk> wrapper = new LambdaQueryWrapper();
        wrapper.eq(Talk::getId, talkId);
        wrapper.eq(Talk::getIsDeleted, 0);
        Talk talk = dao.selectOne(wrapper);
        if (ObjectUtil.isEmpty(talk)) {
            throw new VcaException("该讲座不存在");
        }
        return talk;
    }

    /**
     * @Description:详情
     * @Author: chenBing
     * @Date: 2022/11/3
     */
    public TalkResponse info(String language,Long talkId, String type, String date) {
        TalkResponse talkResponse = new TalkResponse();
        Talk talk = getById(talkId);
        if (talk == null) {
            return talkResponse;
        }
        BeanUtils.copyProperties(talk, talkResponse);
        if (StringUtils.isNotBlank(talk.getMainPictureVideo())) {
            SystemAttachment systemAttachment = systemAttachmentService.getOne(new LambdaQueryWrapper<SystemAttachment>().eq(SystemAttachment::getSattDir, talk.getMainPictureVideo()));
            talkResponse.setMainPictureVideoWidth(systemAttachment.getAttWidth());
            talkResponse.setMainPictureVideoHeight(systemAttachment.getAttHeight());
        }
        User user = userService.getInfo();
        // TODO: 2022/11/28 判断当前课程是否被当前用户收藏
        if (user != null) {
            boolean collect = userCollectionService.count(new LambdaQueryWrapper<UserCollection>().eq(UserCollection::getUid, user.getUid())
                    .eq(UserCollection::getMainType, Constants.ORDER_TYPE_TALK).eq(UserCollection::getMainId, talk.getId())
                    .eq(UserCollection::getType, "collect").eq(UserCollection::getIsDeleted, false)) > 0;
            talkResponse.setIsCollection(collect);
        }
        if("en".equals(language)){
            talkResponse.setName(talkResponse.getNameEn());
            talkResponse.setIntroduction(talkResponse.getIntroductionEn());
        }
        talkResponse.setStatus(talk.getStatus() != 0);
        talkResponse.setCover(talk.getCoverImage());
        if("en".equals(language)){
            talkResponse.setTalkTypeName(talk.getTalkType() == 1 ? "In-person Talk" : "Online Talk");
        }else{
            talkResponse.setTalkTypeName(talk.getTalkType() == 1 ? "线下讲座" : "线上讲座");
        }
        if (talk.getTalkType() == 1) {
            HashMap<String, Object> addressMap = systemGroupDataService.getMapByGid(SysGroupDataConstants.GROUP_DATA_ID_CLIENT_COURSE_ADDRESS, talk.getAddressId());

            Object courseAddress = "";
            Object courseAddressInfo = "";
            Object dest = "";
            if("en".equals(language)){
                courseAddress = addressMap.get("courseAddressEn");
                courseAddressInfo = addressMap.get("courseAddressInfoEn");
                dest = addressMap.get("destEn");
            }else{
                courseAddress = addressMap.get("courseAddress");
                courseAddressInfo = addressMap.get("courseAddressInfo");
                dest = addressMap.get("dest");
            }

            Object lat = addressMap.get("lat");
            Object lon = addressMap.get("lon");
            HashMap<String, Object> talkAddressInfoMap = new HashMap<>();
            talkAddressInfoMap.put("courseAddress", courseAddress);
            talkAddressInfoMap.put("courseAddressInfo", courseAddressInfo);
            talkAddressInfoMap.put("lat", lat);
            talkAddressInfoMap.put("lon", lon);
            talkAddressInfoMap.put("dest", dest);
            talkResponse.setCourseAddress(talkAddressInfoMap);
        }
        JSONArray courseCarouselMap = JSONArray.parseArray(talk.getCarouselMap() == null ? "" : talk.getCarouselMap());
        talkResponse.setCarouselMap(courseCarouselMap);
        int day = Integer.parseInt(systemConfigService.getValueByKey(Constants.TALK_SHOW_DAY));
        String dateToTenDayDate = DateUtil.format(DateUtil.offset(new Date(), DateField.DAY_OF_YEAR, day), "yyyy-MM-dd");
        LambdaQueryWrapper<TalkScheduling> lqw = new LambdaQueryWrapper<TalkScheduling>()
                .eq(TalkScheduling::getStatus, 1)
                .eq(TalkScheduling::getIsDeleted, 0)
                .eq(TalkScheduling::getIsCancel, false)
                .eq(TalkScheduling::getTalkId, talk.getId());
        if (StringUtils.isNotBlank(date)) {
            lqw.eq(TalkScheduling::getSchedulingDate, date)
                    .ge(TalkScheduling::getQuota, 0);
        }
        //todo 如果是线下讲座，那么就需要过滤
        if (!"talk_info_one".equals(type) && talk.getTalkType() == 1) {
            lqw.between(TalkScheduling::getSchedulingDate, DateUtil.format(new Date(), Constants.DATE_FORMAT_DATE), dateToTenDayDate);
        }
        lqw.orderByAsc(TalkScheduling::getSchedulingDate).orderByAsc(TalkScheduling::getSchedulingStartTime);
        List<TalkScheduling> talkSchedulingList = talkSchedulingService.list(lqw);
        List<TalkSchedulingResponse> talkSchedulingResponses = new ArrayList<>();
        talkSchedulingList.forEach(talkScheduling -> {
            TalkSchedulingResponse talkSchedulingResponse = new TalkSchedulingResponse();
            HashMap<String, Object> courseLanguageMap = systemGroupDataService.getMapByGid(SysGroupDataConstants.GROUP_DATA_ID_CLIENT_COURSE_LANGUAGE, talkScheduling.getCourseLanguageId());
            String courseLanguage = "";
            if("en".equals(language)){
                courseLanguage = String.valueOf(courseLanguageMap.get("courseLanguageEn"));
            }else{
                courseLanguage = String.valueOf(courseLanguageMap.get("courseLanguage"));
            }
            talkScheduling.setLanguage(courseLanguage);
            talkScheduling.setSchedulingSeatCount(talkScheduling.getQuota());
            BeanUtils.copyProperties(talkScheduling, talkSchedulingResponse);
            talkSchedulingResponses.add(talkSchedulingResponse);
        });
        //todo 如果是线上讲座，那么就不过滤这个时间
        if (!"talk_info_one".equals(type) && (talk.getTalkType() == 2)) {
            lqw.ge(TalkScheduling::getSchedulingDate, DateUtil.format(DateUtil.beginOfDay(new Date()), Constants.DATE_FORMAT_DATE));
        }

        List<TalkScheduling> talkSchedulings = talkSchedulingService.list(lqw);
        if (talkSchedulings.size() > 0) {
            talkResponse = checkScheduling(language,talkResponse, talkSchedulings, talk);
        } else if (type.equals("talk_list")) {
            return null;
        }

        // TODO: 2022/11/3 设置talkInfo
        TalkInfo talkInfo = talkInfoService.getOne(new LambdaQueryWrapper<TalkInfo>().eq(TalkInfo::getTalkId, talk.getId()));
        TalkInfoVo talkInfoVo = new TalkInfoVo();
        BeanUtils.copyProperties(talkInfo, talkInfoVo);
        if("en".equals(language)){
            talkInfoVo.setDetails(JSONObject.parseArray(talkInfo.getDetailsEn()));
        }else{
            talkInfoVo.setDetails(JSONObject.parseArray(talkInfo.getDetails()));
        }
        // TODO: 2022/10/10 设置相关图集部分
        talkResponse.setTalkInfo(talkInfoVo);
        // TODO: 2022/9/23 处理相关课程推荐
        talkResponse.setEventRecommendations(courseService.getCourseAbouts(language,1, 2, Math.toIntExact(talkId)));
        // TODO: 2022/10/18 处理你可能喜欢的商品 推荐
        talkResponse.setShopRecommendations(courseService.getCourseAbouts(language,2, 2, Math.toIntExact(talkId)));
        // TODO: 2022/12/1 处理相关出版物推荐
        talkResponse.setPublicationRecommendations(courseService.getCourseAbouts(language,3, 2, Math.toIntExact(talkId)));
        //todo: 查询所有排期
        Integer orderQuantityToBeWrittenOff = 0;
        Integer completedOrderQuantity = 0;
        if (user != null) {
            List<TalkScheduling> schedulingList = talkSchedulingService.list(new LambdaQueryWrapper<TalkScheduling>().eq(TalkScheduling::getTalkId, talk.getId()));
            for (TalkScheduling talkScheduling : schedulingList) {
                HashMap<String, Object> map = vcaOrderService.checkPersonAppointmentTalk(user, talk, talkScheduling, Constants.ORDER_TYPE_TALK);
                orderQuantityToBeWrittenOff += (Integer) map.get("orderQuantityToBeWrittenOff");
                completedOrderQuantity += (Integer) map.get("completedOrderQuantity");
            }
        }
        talkResponse.setCompletedOrderQuantity(completedOrderQuantity);
        talkResponse.setOrderQuantityToBeWrittenOff(orderQuantityToBeWrittenOff);
        talkResponse.setIsAppointment(orderQuantityToBeWrittenOff > 0 || completedOrderQuantity > 0 ? true : false);

        return talkResponse;
    }

    @Override
    public TalkResponse infoS(Long talkId, String type, String date) {
        TalkResponse talkResponse = new TalkResponse();
        Talk talk = getById(talkId);
        if (talk == null) {
            return talkResponse;
        }
        BeanUtils.copyProperties(talk, talkResponse);
        int day = Integer.parseInt(systemConfigService.getValueByKey(Constants.TALK_SHOW_DAY));
        String dateToTenDayDate = DateUtil.format(DateUtil.offset(new Date(), DateField.DAY_OF_YEAR, day), "yyyy-MM-dd");
        LambdaQueryWrapper<TalkScheduling> lqw = new LambdaQueryWrapper<TalkScheduling>()
                .eq(TalkScheduling::getStatus, 1)
                .eq(TalkScheduling::getIsDeleted, 0)
                .eq(TalkScheduling::getIsCancel, false)
                .eq(TalkScheduling::getTalkId, talk.getId());
        if (StringUtils.isNotBlank(date)) {
            lqw.eq(TalkScheduling::getSchedulingDate, date)
                    .ge(TalkScheduling::getQuota, 0);
        }
        //todo 如果是线下讲座，那么就需要过滤
        if (!"talk_info_one".equals(type) && talk.getTalkType() == 1) {
            lqw.between(TalkScheduling::getSchedulingDate, DateUtil.format(new Date(), Constants.DATE_FORMAT_DATE), dateToTenDayDate);
        }
        lqw.orderByAsc(TalkScheduling::getSchedulingDate).orderByAsc(TalkScheduling::getSchedulingStartTime);
        //todo 如果是线上讲座，那么就不过滤这个时间
        if (!"talk_info_one".equals(type) && (talk.getTalkType() == 2)) {
            lqw.ge(TalkScheduling::getSchedulingDate, DateUtil.format(DateUtil.beginOfDay(new Date()), Constants.DATE_FORMAT_DATE));
        }
        List<TalkScheduling> talkSchedulings = talkSchedulingService.list(lqw);
        if (talkSchedulings.size() > 0) {
            talkResponse = getPriceOfTalk(talkResponse, talkSchedulings, talk);
        } else {
            return null;
        }
        return talkResponse;
    }

    private TalkResponse checkScheduling(String language,TalkResponse talkResponse, List<TalkScheduling> talkSchedulings, Talk talk) {
        Long scheduledId = 0L;
        List<SchedulingVo> schedulingVos = new ArrayList<>();
        for (TalkScheduling scheduling : talkSchedulings) {
            SchedulingVo schedulingVo = new SchedulingVo();
            // TODO: 2022/11/25 yyyy-MM-dd HH:mm:ss
            String schedulingDate = scheduling.getSchedulingDate() + " " + scheduling.getSchedulingEndTime();
            DateTime dateTime = DateUtil.parse(schedulingDate, "yyyy-MM-dd HH:mm");
            schedulingVo.setScheduledDateTime(dateTime);
            schedulingVo.setScheduled(scheduling.getId());
            schedulingVos.add(schedulingVo);
        }
        if (talk.getTalkType() == 1) {
            DateTime date = DateUtil.date();
            SchedulingVo schedulingV = new SchedulingVo();
            schedulingV.setScheduled(0L);
            schedulingV.setScheduledDateTime(date);
            schedulingVos.add(schedulingV);
            schedulingVos = schedulingVos.stream().sorted(Comparator.comparing(SchedulingVo::getScheduledDateTime)).collect(Collectors.toList());
            for (int i = 0; i < schedulingVos.size(); i++) {
                if (schedulingVos.get(i).getScheduled() == 0 && i + 1 < schedulingVos.size()) {
                    scheduledId = schedulingVos.get(i + 1).getScheduled();
                }
                if (schedulingVos.get(i).getScheduled() == 0 && !(i + 1 < schedulingVos.size())) {
                    scheduledId = schedulingVos.get(i - 1).getScheduled();
                }
            }
        } else {
            scheduledId = schedulingVos.get(0).getScheduled();
        }
        TalkScheduling talkScheduling = talkSchedulingService.getById(scheduledId);
        HashMap<String, Object> courseLanguageMap = systemGroupDataService.getMapByGid(SysGroupDataConstants.GROUP_DATA_ID_CLIENT_COURSE_LANGUAGE, talkScheduling.getCourseLanguageId());
        String courseLanguage = "";
        if("en".equals(language)){
            courseLanguage = String.valueOf(courseLanguageMap.get("courseLanguageEn"));
        }else{
            courseLanguage = String.valueOf(courseLanguageMap.get("courseLanguage"));
        }
        HashMap<Integer, String> languageMap = new HashMap<>();
        languageMap.put(talkScheduling.getCourseLanguageId(), courseLanguage);
        talkResponse.setPrice(talkScheduling.getPrice());
        talkResponse.setOptionalLanguage(languageMap);
        talkResponse.setSchedulingId(talkScheduling.getId());
        talkResponse.setSchedulingDate(talkScheduling.getSchedulingDate());
        talkResponse.setSchedulingStartTime(talkScheduling.getSchedulingStartTime());
        talkResponse.setSchedulingEndTime(talkScheduling.getSchedulingEndTime());
        talkResponse.setRemainingSeatCount(talkScheduling.getQuota());
        talkResponse.setSchedulingStatus(com.vca.common.utils.DateUtil.getSchedulingStatus(talkScheduling.getSchedulingDate(), talkScheduling.getSchedulingStartTime(), talkScheduling.getSchedulingEndTime()));
        talkResponse.setAppointmentStatus(talkScheduling.getStatus() != 0);
        talkResponse.setLiveBroadcastStatus(ObjectUtil.isNull(talkScheduling.getLiveStatus()) ? null : talkScheduling.getLiveStatus());
        if (talkResponse.getTalkType() == 2) {
            talkResponse.setLiveBroadLink(ObjectUtil.isNull(talkScheduling.getLiveId()) ? null : systemConfigService.getValueByKey(Constants.VHALL_LINK) + talkScheduling.getLiveId());
        }

        // TODO: 2022/12/6 判断当前预约是否已截止
        Integer courseEndOrderTimeHour = Integer.valueOf(systemConfigService.getValueByKey(Constants.EXHIBITION_END_ORDER_TIME));
        DateTime offset = cn.hutool.core.date.DateUtil.offset(com.vca.common.utils.DateUtil.strToDate(
                talkScheduling.getSchedulingDate() + " " + talkScheduling.getSchedulingStartTime() + ":00", "yyyy-MM-dd HH:mm:ss"), DateField.HOUR, -courseEndOrderTimeHour);
        long between = cn.hutool.core.date.DateUtil.between(offset, cn.hutool.core.date.DateUtil.date(), DateUnit.SECOND, false);
        if (between >= 0) {
            talkResponse.setIsStopAppointment(false);
        }
        talkResponse.setTotalSeatsLeftForAllScheduledTalk(talkScheduling.getQuota());
        return talkResponse;
    }

    private TalkResponse getPriceOfTalk(TalkResponse talkResponse, List<TalkScheduling> talkSchedulings, Talk talk) {
        Long scheduledId = 0L;
        List<SchedulingVo> schedulingVos = new ArrayList<>();
        for (TalkScheduling scheduling : talkSchedulings) {
            SchedulingVo schedulingVo = new SchedulingVo();
            // TODO: 2022/11/25 yyyy-MM-dd HH:mm:ss
            String schedulingDate = scheduling.getSchedulingDate() + " " + scheduling.getSchedulingEndTime();
            DateTime dateTime = DateUtil.parse(schedulingDate, "yyyy-MM-dd HH:mm");
            schedulingVo.setScheduledDateTime(dateTime);
            schedulingVo.setScheduled(scheduling.getId());
            schedulingVos.add(schedulingVo);
        }
        if (talk.getTalkType() == 1) {
            DateTime date = DateUtil.date();
            SchedulingVo schedulingV = new SchedulingVo();
            schedulingV.setScheduled(0L);
            schedulingV.setScheduledDateTime(date);
            schedulingVos.add(schedulingV);
            schedulingVos = schedulingVos.stream().sorted(Comparator.comparing(SchedulingVo::getScheduledDateTime)).collect(Collectors.toList());
            for (int i = 0; i < schedulingVos.size(); i++) {
                if (schedulingVos.get(i).getScheduled() == 0 && i + 1 < schedulingVos.size()) {
                    scheduledId = schedulingVos.get(i + 1).getScheduled();
                }
                if (schedulingVos.get(i).getScheduled() == 0 && !(i + 1 < schedulingVos.size())) {
                    scheduledId = schedulingVos.get(i - 1).getScheduled();
                }
            }
        } else {
            scheduledId = schedulingVos.get(0).getScheduled();
        }
        TalkScheduling talkScheduling = talkSchedulingService.getById(scheduledId);
        talkResponse.setPrice(talkScheduling.getPrice());
        return talkResponse;
    }

}
